﻿using Common;
using Device;
using hejian_pcba_test.Procdure;
using Hejian_PCBA_Test.Procdure;
using LiveCharts;
using Microsoft.Win32;
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Forms;
using MessageBox = System.Windows.MessageBox;
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;

namespace Hejian_PCBA_Test.ViewModel
{
    internal class MainViewModel : NotifyBase
    {
        public Action SNInputFocusAction;
        private bool Init = false;

        public Config Config { get; set; }

        #region IO状态

        private bool ioUIRefresh = false;

        private bool _IOStart;

        public bool IOStart
        {
            get { return _IOStart; }
            set
            {
                _IOStart = value;
                this.DoNotify();
            }
        }

        private bool _IOEmgStop;

        public bool IOEmgStop
        {
            get { return _IOEmgStop; }
            set
            {
                _IOEmgStop = value;
                this.DoNotify();
            }
        }

        private bool _IOSafeLight;

        public bool IOSafeLight
        {
            get { return _IOSafeLight; }
            set
            {
                _IOSafeLight = value;
                this.DoNotify();
            }
        }

        private bool _IOWiringHarnessesLight;

        public bool IOWiringHarnessesLight
        {
            get { return _IOWiringHarnessesLight; }
            set
            {
                _IOWiringHarnessesLight = value;
                this.DoNotify();
            }
        }

        private bool _IOYUpSensor;

        public bool IOYUpSensor
        {
            get { return _IOYUpSensor; }
            set
            {
                _IOYUpSensor = value;
                this.DoNotify();
            }
        }

        private bool _IOYDownSensor;

        public bool IOYDownSensor
        {
            get { return _IOYDownSensor; }
            set
            {
                _IOYDownSensor = value;
                this.DoNotify();
            }
        }

        public bool IOTrackReset
        {
            get { return _IOTrackReset; }
            set
            {
                _IOTrackReset = value;
                this.DoNotify();
            }
        }

        private bool _IOTrackWork;

        public bool IOTrackWork
        {
            get { return _IOTrackWork; }
            set
            {
                _IOTrackWork = value;
                this.DoNotify();
            }
        }

        private bool _IOYDown;

        public bool IOYDown
        {
            get { return _IOYDown; }
            set
            {
                _IOYDown = value;
                this.DoNotify();
                if (!ioUIRefresh)
                {
                    Global.IOModule.SetDOValue((int)DODefine.YDown, value ? 1 : 0);
                }
            }
        }

        private bool _IOYUp;

        public bool IOYUp
        {
            get { return _IOYUp; }
            set
            {
                _IOYUp = value;
                this.DoNotify();
                if (!ioUIRefresh)
                {
                    Global.IOModule.SetDOValue((int)DODefine.YUp, value ? 1 : 0);
                }
            }
        }

        private bool _IOGreenLight;

        public bool IOGreenLight
        {
            get { return _IOGreenLight; }
            set
            {
                _IOGreenLight = value;
                this.DoNotify();
                if (!ioUIRefresh)
                {
                    Global.IOModule.SetDOValue((int)DODefine.GreenLight, value ? 1 : 0);
                }
            }
        }

        private bool _IOYellowLight;

        public bool IOYellowLight
        {
            get { return _IOYellowLight; }
            set
            {
                _IOYellowLight = value;
                this.DoNotify();
                if (!ioUIRefresh)
                {
                    Global.IOModule.SetDOValue((int)DODefine.YellowLight, value ? 1 : 0);
                }
            }
        }

        private bool _IORedLight;

        public bool IORedLight
        {
            get { return _IORedLight; }
            set
            {
                _IORedLight = value;
                this.DoNotify();
                if (!ioUIRefresh)
                {
                    Global.IOModule.SetDOValue((int)DODefine.RedLight, value ? 1 : 0);
                }
            }
        }

        private bool _IOTrackReset;

        #endregion IO状态

        #region 属性

        private string _sn;

        public string SN
        {
            get { return _sn; }
            set
            {
                _sn = value;
                this.DoNotify();
            }
        }

        private bool? _totalResult;

        public bool? TotalResult
        {
            get { return _totalResult; }
            set
            {
                _totalResult = value;
                this.DoNotify();
            }
        }

        private int _snLength;

        public int SNLength
        {
            get { return _snLength; }
            set
            {
                try
                {
                    Config config = ConfigHelper.Load();
                    config.SNLength = value;
                    ConfigHelper.Save(config);
                    _snLength = value;
                    this.DoNotify();
                }
                catch (Exception ex)
                {
                    Mylog.Error(ex, ex.Message);
                    Log = ex.Message;
                }
            }
        }

        private bool _isTestVoltage;

        /// <summary>
        /// 勾选测试电压
        /// </summary>
        public bool IsTestVoltage
        {
            get { return _isTestVoltage; }
            set
            {
                _isTestVoltage = value;
                this.DoNotify();

                if (Init & value)
                {
                    IsTestResistor = !value;
                    try
                    {
                        LoadVConfigFile();
                    }
                    catch (Exception ex)
                    {
                        Log = $"{ex.Message}!";
                    }
                }
            }
        }

        private bool _isTestResistor;

        /// <summary>
        /// 勾选测试电阻
        /// </summary>
        public bool IsTestResistor
        {
            get { return _isTestResistor; }
            set
            {
                _isTestResistor = value;
                this.DoNotify();

                if (Init)
                {
                    if (Config != null)
                    {
                        Config.TestResistor = value;
                        Config.TestVoltage = !value;
                        ConfigHelper.Save(Config);
                    }
                }

                if (Init & value)
                {
                    if (Config != null)
                    {
                        Config.TestResistor = value;
                        ConfigHelper.Save(Config);
                    }

                    IsTestVoltage = !value;
                    try
                    {
                        LoadRConfigFile();
                    }
                    catch (Exception ex)
                    {
                        Log = $"{ex.Message}!";
                    }
                }
            }
        }

        private string _sysTime;

        /// <summary>
        /// 系统时间
        /// </summary>
        public string SysTime
        {
            get { return _sysTime; }
            set
            {
                _sysTime = value;
                this.DoNotify();
            }
        }

        private bool _autoTest;

        /// <summary>
        /// 是否自动测试，自动测试模式气缸下压，到位后自动开始测试，非自动模式气缸下压到位后不测试
        /// </summary>
        public bool AutoTest
        {
            get { return _autoTest; }
            set
            {
                if (value)
                {
                }
                //如果气缸已经压板，需要先复位
                if (_isCylinderDown)
                {
                    Log = "请先复位设备再操作";
                }
                else
                {
                    if (Init)
                    {
                        if (Config != null)
                        {
                            Config.AutoTest = value;
                            ConfigHelper.Save(Config);
                        }
                    }
                    _autoTest = value;
                    this.DoNotify();
                }
            }
        }

        private bool _onlyViewNG;

        /// <summary>
        /// 仅显示测试NG的测试项，方便定位NG的原件
        /// </summary>
        public bool OnlyViewNG
        {
            get { return _onlyViewNG; }
            set
            {
                _onlyViewNG = value;
                this.DoNotify();
                if (Init)
                {
                    if (Config != null)
                    {
                        Config.OnlyViewNG = value;
                        ConfigHelper.Save(Config);
                    }
                    if (IsTestResistor)
                    {
                        TestResistorResultsView.Refresh();
                    }
                    if (IsTestVoltage)
                    {
                        TestVoltageResultsView.Refresh();
                    }
                }
            }
        }

        #endregion 属性

        #region List Source and filter

        private ObservableCollection<TestResultSingle> _testResistorResults;

        public ObservableCollection<TestResultSingle> TestResistorResults
        {
            get { return _testResistorResults; }
            set
            {
                _testResistorResults = value;
                this.DoNotify();
            }
        }

        private ObservableCollection<TestResultSingle> _testVoltageResults;

        public ObservableCollection<TestResultSingle> TestVoltageResults
        {
            get { return _testVoltageResults; }
            set
            {
                _testVoltageResults = value;
                this.DoNotify();
            }
        }

        private bool Filter(object sender)
        {
            if (sender is TestResultSingle item) // YourItemType 是你的项的类型
            {
                if (OnlyViewNG)
                {
                    return item.Status != true; // 根据某个属性值判断是否显示
                }
                return true;
            }
            return false;
        }

        private ListCollectionView _testResistorResultsView;

        public ListCollectionView TestResistorResultsView
        {
            get { return _testResistorResultsView; }
            set
            {
                _testResistorResultsView = value;
                this.DoNotify();
            }
        }

        private ListCollectionView _testVoltageResultsView;

        public ListCollectionView TestVoltageResultsView
        {
            get { return _testVoltageResultsView; }
            set
            {
                _testVoltageResultsView = value;
                this.DoNotify();
            }
        }

        #endregion List Source and filter

        public List<TestConfig> TestConfigs { get; set; }

        #region command

        public CommandBase TrackStopCommand { get; set; }
        public CommandBase TrackResetCommand { get; set; }
        public CommandBase TrackWorkCommand { get; set; }

        public CommandBase ResetCommand { get; set; }
        public CommandBase StartCommand { get; set; }
        public CommandBase LoadRConfigFileCommand { get; set; }
        public CommandBase LoadVConfigFileCommand { get; set; }
        public CommandBase SaveROutComeFileCommand { get; set; }
        public CommandBase SaveVOutComeFileCommand { get; set; }
        public CommandBase TestSingleResistorCommand { get; set; }
        public CommandBase TestSingleVoltageCommand { get; set; }

        public CommandBase PassNgCountClearCommand { get; set; }

        private void TrackWork(object obj)
        {
            try
            {
                if (_isCylinderDown)
                {
                    Log = "请复位气缸后操作!";
                    return;
                }
                if (_isWiringHarnesses)
                {
                    Log = "线束移除后再执行操作!";
                    return;
                }
                Global.Motor.ToWork();
            }
            catch (Exception ex)
            {
                Mylog.Error(ex, ex.Message);
                Log = ex.Message + "!";
            }
        }

        private void TrackStop(object obj)
        {
            try
            {
                Global.Motor.Stop();
            }
            catch (Exception ex)
            {
                Mylog.Error(ex, ex.Message);
                Log = ex.Message + "!";
            }
        }

        private void TrackReset(object obj)
        {
            try
            {
                if (_isCylinderDown)
                {
                    Log = "请复位气缸后操作!";
                    return;
                }
                if (_isWiringHarnesses)
                {
                    Log = "线束移除后再执行操作!";
                    return;
                }
                Global.Motor.ToOrgin();
            }
            catch (Exception ex)
            {
                Mylog.Error(ex, ex.Message);
                Log = ex.Message + "!";
            }
        }

        private void Reset(object obj)
        {
            Task.Run(() =>
            {
                isReset = true;
                try
                {
                    SNInputFocusAction?.Invoke();

                    TotalResult = null;
                    // 所有tp ->status 设置为未测试
                    if (IsTestResistor)
                    {
                        foreach (var item in TestResistorResults)
                        {
                            item.Status = null;
                            item.ReadValue = 0;
                        }
                    }
                    if (IsTestVoltage)
                    {
                        foreach (var item in TestVoltageResults)
                        {
                            item.Status = null;
                            item.ReadValue = 0;
                        }
                    }
                    if (IsTestVoltage)
                    {
                        MessageBoxResult ret = MessageBoxResult.Cancel;
                        App.Current.Dispatcher.Invoke(() =>
                        {
                            ret = MessageBox.Show("产品是否断电?", "提示", MessageBoxButton.YesNo);
                        });
                        if (ret != MessageBoxResult.Yes)
                        {
                            throw new Exception("产品未断电,请断电后复位");
                        }
                    }
                    if (!_isCylinderUp)
                    {
                        Global.IOModule.SetDOValue((int)DODefine.YUp, 1);
                        Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                        bool isTimeout = false;
                        Task.Run(() =>
                        {
                            Thread.Sleep(7000);
                            isTimeout = true;
                        });
                        while (!_isCylinderUp)
                        {
                            if (_isEmgStop)
                            {
                                Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                                Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                                throw new Exception("设备急停");
                            }
                            if (_isSafeDoorOn)
                            {
                                Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                                Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                                throw new Exception("安全光栅感应");
                            }
                            if (isTimeout)
                            {
                                break;
                            }
                            Thread.Sleep(50);
                        }
                        if (isTimeout)
                        {
                            throw new Exception("气缸复位超时");
                        }
                        else
                        {
                            Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                        }
                    }
                    TrackToOrgin();
                    _isReady = true;
                    Global.SetDevStatus(DevStatus.Wait);
                    Log = "复位完成";
                    SNInputFocusAction?.Invoke();
                    SN = "";
                }
                catch (Exception ex)
                {
                    Log = $"{ex.Message}!";
                    Mylog.Error(ex, ex.Message);
                }
                finally
                {
                    isReset = false;
                }
            });
        }

        /// <summary>
        /// 启动按钮按下
        /// </summary>
        /// <param name="obj"> </param>
        private void Start(object obj)
        {
            Task.Run(() =>
            {
                if (_isTesting)
                {
                    return;
                }
                _isTesting = true;
                var tmp = Global.IOModule.ListDIChanged.FindIndex(x => x.DIndex == (int)DIDefine.Start & x.ConditionValue == false);
                try
                {
                    Global.IOModule.ListDIChanged[tmp].DIChangedEvent = null;

                    #region 轨道到位

                    TrackToWork();
                    //Thread.Sleep(19000);

                    #endregion 轨道到位

                    #region 气缸下压

                    // 气缸下压
                    if (_isEmgStop)
                    {
                        Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                        Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                        throw new Exception("设备急停");
                    }
                    if (_isSafeDoorOn)
                    {
                        Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                        Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                        throw new Exception("安全光栅感应");
                    }

                    Global.IOModule.SetDOValue((int)DODefine.YDown, 1);
                    bool isTimeout = false;
                    Task.Run(() =>
                    {
                        Thread.Sleep(7000);
                        isTimeout = true;
                    });
                    while (!_isCylinderDown)
                    {
                        if (_isEmgStop)
                        {
                            Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                            Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                            throw new Exception("设备急停");
                        }
                        if (_isSafeDoorOn)
                        {
                            Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                            Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                            throw new Exception("安全光栅感应");
                        }
                        if (isTimeout)
                            break;
                    }

                    Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                    if (isTimeout)
                    {
                        throw new Exception("气缸到位超时");
                    }

                    Log = "气缸到位";

                    if (AutoTest & _isReady)
                    {
                        Task.Run(() =>
                        {
                            StartTest();
                        });
                    }

                    #endregion 气缸下压
                }
                catch (Exception ex)
                {
                    Global.IOModule.SetDOValue((int)DODefine.YDown, 0); ;

                    Mylog.Error(ex, ex.Message);
                    Log = ex.Message + "!";
                }
                finally
                {
                    Global.IOModule.ListDIChanged[tmp].DIChangedEvent = StartFreeActionEvent;
                    _isTesting = false;
                }
            });
        }

        private void TrackToOrgin()
        {
            if (_isCylinderDown)
            {
                throw new Exception("气缸复位后再执行操作");
            }
            if (_isWiringHarnesses)
            {
                throw new Exception("线束移除后再执行操作");
            }
            Global.Motor.ToOrgin();
            bool timeout = false;
            Task.Run(() =>
            {
                Thread.Sleep(20000);
                timeout = true;
            });
            while (!_isTrackReset)
            {
                Thread.Sleep(100);
                if (timeout)
                {
                    break;
                }
            }
            if (timeout)
            {
                throw new Exception("轨道复位超时");
            }
        }

        private void TrackToWork()
        {
            if (_isCylinderDown)
            {
                throw new Exception("气缸复位后再执行操作");
            }
            if (_isWiringHarnesses)
            {
                throw new Exception("线束移除后再执行操作");
            }
            Global.Motor.ToWork();
            bool timeout = false;
            Task.Run(() =>
            {
                Thread.Sleep(20000);
                timeout = true;
            });
            while (!_isTrackWork)
            {
                Thread.Sleep(100);
                if (timeout)
                {
                    break;
                }
            }
            if (timeout)
            {
                throw new Exception("轨道到位超时");
            }
        }

        private void LoadRConfigFile(object obj)
        {
            try
            {
                // 创建一个新的 OpenFileDialog 对象
                OpenFileDialog openFileDialog = new OpenFileDialog();

                // 设置对话框的标题
                openFileDialog.Title = "选择烧录文件";

                openFileDialog.RestoreDirectory = true;

                // 设置过滤器，限制可以选择的文件类型（可选）
                openFileDialog.Filter = "烧录文件 (*.csv)|*.csv|所有文件 (*.*)|*.*";

                // 打开对话框并检查用户是否点击了 "打开" 按钮
                if (openFileDialog.ShowDialog() == true)
                {
                    // 用户已选择文件，您可以执行所需的操作
                    string selectedFilePath = openFileDialog.FileName;
                    //Console.WriteLine("选择的文件路径：" + selectedFilePath);
                    ConfigRFilePath = selectedFilePath;
                    Config.ConfigRFilePath = ConfigRFilePath;
                    ConfigHelper.Save(Config);
                    LoadRConfigFile();
                }
            }
            catch (Exception ex)
            {
                Log = ex.Message;
                Mylog.Error(ex, ex.Message);
            }
        }

        private void LoadVConfigFile(object obj)
        {
            try
            {
                // 创建一个新的 OpenFileDialog 对象
                OpenFileDialog openFileDialog = new OpenFileDialog();

                // 设置对话框的标题
                openFileDialog.Title = "选择烧录文件";

                openFileDialog.RestoreDirectory = true;

                // 设置过滤器，限制可以选择的文件类型（可选）
                openFileDialog.Filter = "烧录文件 (*.csv)|*.csv|所有文件 (*.*)|*.*";

                // 打开对话框并检查用户是否点击了 "打开" 按钮
                if (openFileDialog.ShowDialog() == true)
                {
                    // 用户已选择文件，您可以执行所需的操作
                    string selectedFilePath = openFileDialog.FileName;
                    //Console.WriteLine("选择的文件路径：" + selectedFilePath);
                    ConfigVFilePath = selectedFilePath;
                    Config.ConfigVFilePath = ConfigVFilePath;
                    ConfigHelper.Save(Config);
                    LoadVConfigFile();
                }
            }
            catch (Exception ex)
            {
                Log = ex.Message;
                Mylog.Error(ex, ex.Message);
            }
        }

        private void TestSingleResistor(object obj)
        {
            Task.Run(() =>
            {
                try
                {
                    if (!_isCylinderDown)
                    {
                        Log = "气缸未到位!";
                        return;
                    }

                    if (SelectedResistorTP is null)
                    {
                        Log = "请选择一个电阻测试项!";
                        return;
                    }
                    // 切换万用表功能
                    DM3058E.SetFunction(Function.WR2);

                    TestOneResistor(SelectedResistorTP);
                }
                catch (Exception ex)
                {
                    Mylog.Error(ex, ex.Message);
                    Log = ex.Message;
                }
                finally
                {
                }
            });
        }

        private void TestSingleVoltage(object obj)
        {
            Task.Run(() =>
            {
                try
                {
                    if (!_isCylinderDown)
                    {
                        Log = "气缸未到位!";
                        return;
                    }
                    if (SelectedVoltageTP is null)
                    {
                        Log = "请选择一个电压测试项!";
                        return;
                    }
                    // 切换万用表功能
                    DM3058E.SetFunction(Function.DCV);

                    TestOneVoltage(SelectedVoltageTP);
                }
                catch (Exception ex)
                {
                    Mylog.Error(ex, ex.Message);
                    Log = ex.Message;
                }
                finally
                {
                }
            });
        }

        private void PassNgCountClear(object obj)
        {
            NgCount = 0;
            OkCount = 0;
        }

        #endregion command

        public MainViewModel()
        {
            TotalResult = null;
            AutoTest = false;
            _isReady = true;
            SN = "";

            IsTestResistor = true;
            IsTestVoltage = false;

            TestResistorResults = new ObservableCollection<TestResultSingle>();
            TestVoltageResults = new ObservableCollection<TestResultSingle>();

            TestResistorResultsView = new ListCollectionView(TestResistorResults);
            TestResistorResultsView.Filter = Filter;

            TestVoltageResultsView = new ListCollectionView(TestVoltageResults);
            TestVoltageResultsView.Filter = Filter;

            TestSingleResistorCommand = new CommandBase(TestSingleResistor);
            TestSingleVoltageCommand = new CommandBase(TestSingleVoltage);

            TrackResetCommand = new CommandBase(TrackReset);
            TrackStopCommand = new CommandBase(TrackStop);
            TrackWorkCommand = new CommandBase(TrackWork);
            LoadRConfigFileCommand = new CommandBase(LoadRConfigFile);
            LoadVConfigFileCommand = new CommandBase(LoadVConfigFile);
            SaveROutComeFileCommand = new CommandBase(SaveROutComeFile);
            SaveVOutComeFileCommand = new CommandBase(SaveVOutComeFile);
            StartCommand = new CommandBase(Start);
            ResetCommand = new CommandBase(Reset);
            PassNgCountClearCommand = new CommandBase(PassNgCountClear);
            Task.Run(() =>
            {
                try
                {
                    Config = ConfigHelper.Load();

                    PointLabel = chartPoint => string.Format("{0} ({1:P})", chartPoint.Y, chartPoint.Participation);

                    OkCount = Config.OKCount;
                    NgCount = Config.NGCount;
                    IsTestResistor = Config.TestResistor;
                    IsTestVoltage = Config.TestVoltage;
                    OnlyViewNG = Config.OnlyViewNG;
                    AutoTest = Config.AutoTest;

                    ConfigRFilePath = Config.ConfigRFilePath;
                    ConfigVFilePath = Config.ConfigVFilePath;
                    OutComeRFilePath = Config.OutComeRFilePath;
                    OutComeVFilePath = Config.OutComeVFilePath;
                    SNLength = Config.SNLength;
                    if (IsTestResistor)
                    {
                        LoadRConfigFile();
                    }
                    if (IsTestVoltage)
                    {
                        LoadVConfigFile();
                    }

                    Global.IOModule = new IOModule();
                    Global.IOModule.IOModuleType = IOModuleType.All;
                    Global.IOModule.Connect();

                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.Start, ConditionValue = true, DIChangedEvent = StartActionEvent });
                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.Start, ConditionValue = false, DIChangedEvent = StartFreeActionEvent });

                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.EmgStop, ConditionValue = false, DIChangedEvent = EmgStopActionEvent });
                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.EmgStop, ConditionValue = true, DIChangedEvent = EmgCancelAction });

                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.TrackReset, ConditionValue = true, DIChangedEvent = TrackNoneResetEvent });
                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.TrackReset, ConditionValue = false, DIChangedEvent = TrackResetEvent });

                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.TrackWork, ConditionValue = true, DIChangedEvent = TrackNoneWorkEvent });
                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.TrackWork, ConditionValue = false, DIChangedEvent = TrackWorkEvent });

                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.SafeLight, ConditionValue = false, DIChangedEvent = SafeLightActionEvent });
                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.SafeLight, ConditionValue = true, DIChangedEvent = SafeLightNoneActionEvent });

                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.WiringHarnessesLight, ConditionValue = true, DIChangedEvent = WiringHarnessesLightActionEvent });
                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.WiringHarnessesLight, ConditionValue = false, DIChangedEvent = WiringHarnessesLightNoneActionEvent });

                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.YDownSenSor, ConditionValue = true, DIChangedEvent = CylinderDownActionEvent });
                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.YDownSenSor, ConditionValue = false, DIChangedEvent = CylinderDownNoneActionEvent });

                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.YUpSensor, ConditionValue = true, DIChangedEvent = CylinderUpActionEvent });
                    Global.IOModule.ListDIChanged.Add(new DIChanged { DIndex = (int)DIDefine.YUpSensor, ConditionValue = false, DIChangedEvent = CylinderUpNoneActionEvent });
                    Global.SetDevStatus(DevStatus.Wait);

                    Task.Run(() =>
                    {
                        while (true)
                        {
                            ioUIRefresh = true;

                            IOStart = Global.IOModule.GetDIValue((int)DIDefine.Start);
                            IOEmgStop = Global.IOModule.GetDIValue((int)DIDefine.EmgStop);
                            IOSafeLight = Global.IOModule.GetDIValue((int)DIDefine.SafeLight);
                            IOWiringHarnessesLight = Global.IOModule.GetDIValue((int)DIDefine.WiringHarnessesLight);
                            IOYUpSensor = Global.IOModule.GetDIValue((int)DIDefine.YUpSensor);
                            IOYDownSensor = Global.IOModule.GetDIValue((int)DIDefine.YDownSenSor);
                            IOTrackReset = Global.IOModule.GetDIValue((int)DIDefine.TrackReset);
                            IOTrackWork = Global.IOModule.GetDIValue((int)DIDefine.TrackWork);

                            IOYDown = Global.IOModule.GetDOValue((int)DODefine.YDown);
                            IOYUp = Global.IOModule.GetDOValue((int)DODefine.YUp);
                            IOGreenLight = Global.IOModule.GetDOValue((int)DODefine.GreenLight);
                            IOYellowLight = Global.IOModule.GetDOValue((int)DODefine.YellowLight);
                            IORedLight = Global.IOModule.GetDOValue((int)DODefine.RedLight);

                            ioUIRefresh = false;
                            Thread.Sleep(500);
                        }
                    });
                    Global.Relay = new Relay();
                    Global.Relay.Connect(Config.RelayPort);

                    DM3058E.Connect(Config.DM3058EPort);

                    var Motor = new LC10P();
                    Motor.Speed = Config.MotorSpeed;
                    Motor.Connect(Config.LC10PPort, 19200);
                    Motor.Init();
                    Global.Motor = Motor;
                    Log = "初始化成功";

                    SNInputFocusAction?.Invoke();
                }
                catch (Exception ex)
                {
                    Log = ex.Message;
                    Mylog.Error(ex, ex.Message);
                }
                finally
                {
                    Init = true;
                }
            });
        }

        private bool isReset = false;

        private void StartTest()
        {
            isReset = false;
            _isTesting = true;
            Global.SetDevStatus(DevStatus.OK);
            try
            {
                Stopwatch sw = Stopwatch.StartNew();
                TotalResult = null;
                // 所有tp ->status 设置为未测试
                if (IsTestResistor)
                {
                    foreach (var item in TestResistorResults)
                    {
                        item.Status = null;
                        item.ReadValue = 0;
                    }
                }

                if (IsTestVoltage)
                {
                    foreach (var item in TestVoltageResults)
                    {
                        item.Status = null;
                        item.ReadValue = 0;
                    }
                    MessageBoxResult ret = MessageBoxResult.Cancel;
                    App.Current.Dispatcher.Invoke(() =>
                    {
                        ret = MessageBox.Show("产品是否上电?", "提示", MessageBoxButton.YesNo);
                    });
                    if (ret != MessageBoxResult.Yes)
                    {
                        throw new Exception("产品未上电,测试结束");
                    }
                }

                if (SN is null | SNLength != SN.Length)
                {
                    throw new Exception("SN码长度异常");
                }

                int count = -1;

                #region 测试电阻

                if (IsTestResistor)
                {
                    Log = "开始测试电阻";
                    // 切换功能
                    DM3058E.SetFunction(Function.WR2);
                    foreach (var item in TestResistorResults)
                    {
                        SelectedResistorTP = item;
                        TestOneResistor(item);
                    }
                    count = TestResistorResults.Where(r => r.Status == false).Count();
                }

                #endregion 测试电阻

                #region 测试电压

                if (IsTestVoltage)
                {
                    Log = "开始测试电压";
                    // 切换功能
                    DM3058E.SetFunction(Function.DCV);
                    foreach (var item in TestVoltageResults)
                    {
                        SelectedVoltageTP = item;
                        TestOneVoltage(item);
                    }
                    count = TestVoltageResults.Where(r => r.Status == false).Count();
                }

                #endregion 测试电压

                if (count == 0)
                {
                    Log = "测试PASS";
                    OkCount++;
                    // ok
                    TotalResult = true;
                    Global.SetDevStatus(DevStatus.Wait);
                }
                else
                {
                    Log = "测试NG，开始复测";
                    // ng 复测 气缸抬起
                    WaitCylinderUp();

                    #region 气缸下压

                    // 气缸下压
                    if (_isEmgStop)
                    {
                        Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                        Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                        throw new Exception("设备急停");
                    }
                    if (_isSafeDoorOn)
                    {
                        Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                        Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                        throw new Exception("安全光栅感应");
                    }
                    Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                    Global.IOModule.SetDOValue((int)DODefine.YDown, 1);
                    bool isTimeout = false;
                    Task.Run(() =>
                    {
                        Thread.Sleep(10000);
                        isTimeout = true;
                    });
                    while (!_isCylinderDown)
                    {
                        if (_isEmgStop)
                        {
                            Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                            Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                            throw new Exception("设备急停");
                        }
                        if (_isSafeDoorOn)
                        {
                            Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                            Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                            throw new Exception("安全光栅感应");
                        }
                        if (isTimeout)
                            break;
                    }
                    Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                    Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                    if (isTimeout)
                    {
                        throw new Exception("气缸到位超时");
                    }

                    Log = "气缸到位";

                    #endregion 气缸下压

                    #region 复测电阻

                    if (IsTestResistor)
                    {
                        foreach (var item in TestResistorResults)
                        {
                            if (item.Status == false)
                            {
                                SelectedResistorTP = item;
                                TestOneResistor(item);
                            }
                        }

                        count = TestResistorResults.Where(r => r.Status == false).Count();
                    }

                    #endregion 复测电阻

                    #region 复测电压

                    if (IsTestVoltage)
                    {
                        foreach (var item in TestVoltageResults)
                        {
                            if (item.Status == false)
                            {
                                SelectedVoltageTP = item;
                                TestOneVoltage(item);
                            }
                        }
                        count = TestVoltageResults.Where(r => r.Status == false).Count();
                    }

                    #endregion 复测电压

                    if (count == 0)
                    {
                        // ok
                        TotalResult = true;
                        Log = "复测PASS";
                        Global.SetDevStatus(DevStatus.Wait);
                        OkCount++;
                    }
                    else
                    {
                        NgCount++;
                        Log = "复测NG!";
                        Global.SetDevStatus(DevStatus.NG);

                        TotalResult = false;
                    }
                }

                var tmp = (int)(sw.ElapsedMilliseconds / 1000);
                Log = $"测试耗时{tmp / 60}分钟{tmp % 60}秒";

                NoteResult(count == 0);
                Log = "测试报告已生成";

                if (IsTestVoltage)
                {
                    MessageBoxResult ret = MessageBoxResult.Cancel;
                    App.Current.Dispatcher.Invoke(() =>
                    {
                        ret = MessageBox.Show("产品是否断电?", "提示", MessageBoxButton.YesNo);
                    });
                    if (ret != MessageBoxResult.Yes)
                    {
                        throw new Exception("产品未断电,请断电后复位");
                    }
                }

                WaitCylinderUp();   //气缸复位

                TrackToOrgin(); //轨道复位
            }
            catch (Exception ex)
            {
                Global.SetDevStatus(DevStatus.NG);

                _isReady = false;
                Log = ex.Message + "!";
                Mylog.Error(ex, ex.Message);
            }
            finally
            {
                _isTesting = false;
                SN = "";
            }
            SNInputFocusAction?.Invoke();
        }

        private void WaitCylinderUp()
        {
            Global.IOModule.SetDOValue((int)DODefine.YUp, 1);
            Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
            bool isTimeout = false;
            Task.Run(() =>
            {
                Thread.Sleep(7000);
                isTimeout = true;
            });
            while (!_isCylinderUp)
            {
                if (_isEmgStop)
                {
                    Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                    Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                    throw new Exception("设备急停");
                }
                if (_isSafeDoorOn)
                {
                    Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                    Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                    throw new Exception("安全光栅感应");
                }
                if (isTimeout)
                {
                    break;
                }
                Thread.Sleep(50);
            }
            if (isTimeout)
            {
                throw new Exception("气缸复位超时");
            }
            Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
            Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
            Log = "气缸复位完成";
        }

        private void SafeLightNoneActionEvent()
        {
            _isSafeDoorOn = false;
        }

        private void SafeLightActionEvent()
        {
            _isSafeDoorOn = true;
        }

        private void WiringHarnessesLightNoneActionEvent()
        {
            _isWiringHarnesses = false;
        }

        private void WiringHarnessesLightActionEvent()
        {
            _isWiringHarnesses = true;
        }

        private void CylinderUpNoneActionEvent()
        {
            _isCylinderUp = false;
        }

        private void CylinderDownNoneActionEvent()
        {
            _isCylinderDown = false;
        }

        private void CylinderUpActionEvent()
        {
            _isCylinderUp = true;
        }

        private void CylinderDownActionEvent()
        {
            _isCylinderDown = true;
        }

        private bool _isTrackWork = false;
        private bool _isTrackReset = false;
        private bool _isEmgStop = false;
        private bool _isCylinderDown = false;
        private bool _isCylinderUp = false;
        private bool _isSafeDoorOn = false;
        private bool _isWiringHarnesses = false;
        private bool _isTesting = false;
        private bool _isReady = false;  //准备就绪时才可以开测

        private void TrackWorkEvent()
        {
            _isTrackWork = true;
        }

        private void TrackNoneWorkEvent()
        {
            _isTrackWork = false;
        }

        private void TrackResetEvent()
        {
            _isTrackReset = true;
        }

        private void TrackNoneResetEvent()
        {
            _isTrackReset = false;
        }

        private void EmgCancelAction()
        {
            _isEmgStop = false;
        }

        private void EmgStopActionEvent()
        {
            _isEmgStop = true;
        }

        private void StartFreeActionEvent()
        {
            try
            {
                if (!AutoTest)
                {
                    if (Global.IOModule.GetDOValue((int)DODefine.YDown))
                    {
                        Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                        Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                    }
                }
            }
            catch (Exception ex)
            {
                Mylog.Error(ex, ex.Message);
                Log = ex.Message;
            }
        }

        private void StartActionEvent()
        {
            try
            {
                if (AutoTest)
                {
                    Start(null);
                    // 自动测试
                }
                else
                {
                    // 手动测试

                    if (_isEmgStop)
                    {
                        Log = "设备急停!";
                        Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                        Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                        return;
                    }
                    if (_isSafeDoorOn)
                    {
                        Log = "安全光栅感应!";
                        Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                        Global.IOModule.SetDOValue((int)DODefine.YDown, 0);
                        return;
                    }
                    if (!_isTrackWork)
                    {
                        Log = "轨道未到位!";
                        return;
                    }

                    Global.IOModule.SetDOValue((int)DODefine.YUp, 0);
                    Global.IOModule.SetDOValue((int)DODefine.YDown, _isCylinderDown ? 0 : 1);
                }
            }
            catch (Exception ex)
            {
                Mylog.Error(ex, ex.Message);
                Log = ex.Message;
            }
        }

        /// <summary>
        /// 测试单个电阻
        /// </summary>
        /// <param name="testResultSingle"> </param>
        private void TestOneResistor(TestResultSingle testResultSingle)
        {
            Log = $"测试TP点[{testResultSingle.TP}]";

            //切换量程
            DM3058E.SetRange(testResultSingle.UpperLimit);

            //切换继电器
            Global.Relay.SetDO(testResultSingle.RelayNo, testResultSingle.GndRelayNo);

            Thread.Sleep(testResultSingle.SleepTime);

            for (int i = 0; i < testResultSingle.SleepTime; i++)
            {
                if (_isEmgStop)
                {
                    throw new Exception("设备急停");
                }
                if (isReset)
                {
                    throw new Exception("测试中断!");
                }
                Thread.Sleep(200);
                i += 200;
            }

            //读取阻值
            testResultSingle.ReadValue = Math.Round(Device.DM3058E.GetValue(), 2) - testResultSingle.InnerTesistance;   //edit by fengxl 20231025 读取电阻减去内阻

            //判定结果
            testResultSingle.UpdateStatus();
        }

        private void TestOneVoltage(TestResultSingle testResultSingle)
        {
            Log = $"测试TP点[{testResultSingle.TP}]";

            //切换量程
            DM3058E.SetRange(testResultSingle.UpperLimit);

            //切换继电器
            Global.Relay.SetDO(testResultSingle.RelayNo, testResultSingle.GndRelayNo);

            for (int i = 0; i < testResultSingle.SleepTime; i++)
            {
                if (_isEmgStop)
                {
                    throw new Exception("设备急停");
                }
                if (isReset)
                {
                    throw new Exception("测试中断!");
                }
                Thread.Sleep(200);
                i += 200;
            }
            //读取阻值
            testResultSingle.ReadValue = Math.Round(Device.DM3058E.GetValue(), 2) - testResultSingle.InnerTesistance;   //edit by fengxl 20231025 读取电阻减去内阻

            //判定结果
            testResultSingle.UpdateStatus();
        }

        private TestResultSingle _selectedResistorTP;

        public TestResultSingle SelectedResistorTP
        {
            get { return _selectedResistorTP; }
            set
            {
                _selectedResistorTP = value;
                this.DoNotify();
            }
        }

        private TestResultSingle _selectedVoltageTP;

        public TestResultSingle SelectedVoltageTP
        {
            get { return _selectedVoltageTP; }
            set
            {
                _selectedVoltageTP = value;
                this.DoNotify();
            }
        }

        #region LiveChart

        public class Chart
        {
            public int Value { get; set; }
        }

        public Func<ChartPoint, string> PointLabel { get; set; }
        public ObservableCollection<Chart> ChartData { get; set; }

        private int _okCount;

        public int OkCount
        {
            get { return _okCount; }
            set
            {
                _okCount = value;
                this.DoNotify();
                if (Config != null)
                {
                    Config.OKCount = value;
                    ConfigHelper.Save(Config);
                }
            }
        }

        private int _ngCount;

        public int NgCount
        {
            get { return _ngCount; }
            set
            {
                _ngCount = value;
                this.DoNotify();
                if (Config != null)
                {
                    Config.NGCount = value;
                    ConfigHelper.Save(Config);
                }
            }
        }

        #endregion LiveChart

        #region 配置文件路径

        private string _configRFilePath;

        public string ConfigRFilePath
        {
            get { return _configRFilePath; }
            set
            {
                _configRFilePath = value;
                this.DoNotify();
            }
        }

        private string _configVFilePath;

        public string ConfigVFilePath
        {
            get { return _configVFilePath; }
            set
            {
                _configVFilePath = value;
                this.DoNotify();
            }
        }

        #endregion 配置文件路径

        private string _outComeRFilePath;

        public string OutComeRFilePath
        {
            get { return _outComeRFilePath; }
            set
            {
                _outComeRFilePath = value;
                this.DoNotify();
            }
        }

        private string _outComeVFilePath;

        public string OutComeVFilePath
        {
            get { return _outComeVFilePath; }
            set
            {
                _outComeVFilePath = value;
                this.DoNotify();
            }
        }

        #region 加载配置文件

        private void LoadRConfigFile()
        {
            TestResistorResults = new ObservableCollection<TestResultSingle>();
            //TestResults.CollectionChanged += TestResults_CollectionChanged;
            TestResistorResultsView = new ListCollectionView(TestResistorResults);
            TestResistorResultsView.Filter = Filter;

            var testConfig = TestConfig.LoadConfig(ConfigRFilePath);

            foreach (var config in testConfig)
            {
                TestResistorResults.Add(new TestResultSingle
                {
                    InnerTesistance = config.Offset,
                    SleepTime = config.SleepTime,
                    TP = config.TP,
                    Status = null,
                    ReadValue = 0,
                    GndRelayNo = config.GndRelayNo,
                    RelayNo = config.RelayNo,
                    LowerLimit = config.LowerLimit,
                    UpperLimit = config.UpperLimit,
                });
            }
        }

        private void LoadVConfigFile()
        {
            TestVoltageResults = new ObservableCollection<TestResultSingle>();
            //TestResults.CollectionChanged += TestResults_CollectionChanged;
            TestVoltageResultsView = new ListCollectionView(TestVoltageResults);
            TestVoltageResultsView.Filter = Filter;
            var testConfig = TestConfig.LoadConfig(ConfigVFilePath);
            foreach (var config in testConfig)
            {
                TestVoltageResults.Add(new TestResultSingle
                {
                    InnerTesistance = config.Offset,
                    SleepTime = config.SleepTime,
                    TP = config.TP,
                    Status = null,
                    ReadValue = 0,
                    GndRelayNo = config.GndRelayNo,
                    RelayNo = config.RelayNo,
                    LowerLimit = config.LowerLimit,
                    UpperLimit = config.UpperLimit,
                });
            }
        }

        private void SaveVOutComeFile(object obj)
        {
            try
            {
                FolderBrowserDialog dialog = new FolderBrowserDialog();
                // 设置对话框的标题
                dialog.Description = "请选择文件路径";

                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    string selectedFilePath = dialog.SelectedPath;
                    //Console.WriteLine("选择的文件路径：" + selectedFilePath);
                    OutComeVFilePath = selectedFilePath;
                    Config.OutComeVFilePath = OutComeVFilePath;
                    ConfigHelper.Save(Config);
                }
            }
            catch (Exception ex)
            {
                Log = ex.Message;
                Mylog.Error(ex, ex.Message);
            }
        }

        private void SaveROutComeFile(object obj)
        {
            try
            {
                FolderBrowserDialog dialog = new FolderBrowserDialog();
                // 设置对话框的标题
                dialog.Description = "请选择文件路径";

                if (dialog.ShowDialog() == DialogResult.OK)
                {
                    string selectedFilePath = dialog.SelectedPath;
                    //Console.WriteLine("选择的文件路径：" + selectedFilePath);
                    OutComeRFilePath = selectedFilePath;
                    Config.OutComeRFilePath = OutComeRFilePath;
                    ConfigHelper.Save(Config);
                }
            }
            catch (Exception ex)
            {
                Log = ex.Message;
                Mylog.Error(ex, ex.Message);
            }
        }

        #endregion 加载配置文件

        private void TestResults_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            TestResistorResults = sender as ObservableCollection<TestResultSingle>;
        }

        #region 记录测试结果

        /// <summary>
        /// 记录测试结果
        /// </summary>
        /// <param name="ret"> </param>
        private void NoteResult(bool ret)
        {
            string dir = "./Data";
            string retDesc = ret ? "PASS" : "FAILED";
            //string sample = Environment.CurrentDirectory + "\\sample.xlsx";
            //WriteToCsv(TestResults, path);
            if (IsTestResistor)
            {
                if (string.IsNullOrEmpty(OutComeRFilePath))
                {
                    OutComeRFilePath = dir;
                }
                if (!Directory.Exists(OutComeRFilePath))
                {
                    Directory.CreateDirectory(OutComeRFilePath);
                }
                string path = @$"{OutComeRFilePath}/{SN}-{DateTime.Now.ToString("yyyyMMddHHmmss")}-{retDesc}.xlsx";
                if (File.Exists(path))
                {
                    File.Delete(path);
                }
                WriteToXlsx(TestResistorResults, path, ret);
            }
            else
            {
                if (string.IsNullOrEmpty(OutComeVFilePath))
                {
                    OutComeVFilePath = dir;
                }
                if (!Directory.Exists(OutComeVFilePath))
                {
                    Directory.CreateDirectory(OutComeVFilePath);
                }
                string path = @$"{OutComeVFilePath}/{SN}-{DateTime.Now.ToString("yyyyMMddHHmmss")}-{retDesc}.xlsx";
                if (File.Exists(path))
                {
                    File.Delete(path);
                }
                WriteToXlsx(TestVoltageResults, path, ret);
            }
        }

        /// <summary>
        /// 输出xlsx
        /// </summary>
        /// <param name="data">     </param>
        /// <param name="filePath"> </param>
        private void WriteToXlsx(ObservableCollection<TestResultSingle> data, string filePath, bool result)
        {
            ExcelPackage.LicenseContext = LicenseContext.NonCommercial;

            // 创建一个新的Excel包
            using (var package = new ExcelPackage())
            {
                // 添加一个工作表
                var worksheet = package.Workbook.Worksheets.Add("Sheet1");

                // 写入头
                worksheet.Cells["A1"].Value = "二维码";
                worksheet.Cells["B1"].Value = "终测结果";
                worksheet.Cells["C1"].Value = "TP点";

                string unit = "";
                if (IsTestResistor)
                {
                    unit = "Ω";
                    worksheet.Cells["D1"].Value = "阻值";
                    worksheet.Cells["E1"].Value = "测试结果";
                    worksheet.Cells["F1"].Value = "阻值下限";
                    worksheet.Cells["G1"].Value = "阻值上限";
                }
                else
                {
                    unit = "V";
                    worksheet.Cells["D1"].Value = "电压值";
                    worksheet.Cells["E1"].Value = "测试结果";
                    worksheet.Cells["F1"].Value = "电压下限";
                    worksheet.Cells["G1"].Value = "电压上限";
                }

                worksheet.Cells["H1"].Value = "测试延时";

                worksheet.Cells["A2"].Value = SN;
                worksheet.Cells["B2"].Value = result ? "PASS" : "FAILED";

                // 循环写入数据
                int index = 2;

                foreach (var item in data)
                {
                    worksheet.Cells[$"C{index}"].Value = item.TP;
                    worksheet.Cells[$"D{index}"].Value = item.ReadValue + unit;
                    worksheet.Cells[$"E{index}"].Value = (item.Status == true) ? "Pass" : "FAILED";
                    worksheet.Cells[$"F{index}"].Value = item.LowerLimit + unit;
                    worksheet.Cells[$"G{index}"].Value = item.UpperLimit + unit;
                    worksheet.Cells[$"H{index}"].Value = item.SleepTime + "ms";
                    index++;
                }

                // 保存Excel文件
                var fileInfo = new FileInfo(filePath);
                package.SaveAs(fileInfo);
            }
        }

        #endregion 记录测试结果

        #region 显示日志

        private string _log;

        public string Log
        {
            get { return _log; }
            set
            {
                System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                {
                    _log = value;
                    this.DoNotify();
                }));
            }
        }

        #endregion 显示日志
    }
}